import asyncio
import logging
from pymodbus.server import StartAsyncTcpServer
from pymodbus.datastore import ModbusSequentialDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
from pymodbus.device import ModbusDeviceIdentification

# 服务器监听的 IP 和端口
HOST = "0.0.0.0"  # 监听所有网络接口
PORT = 502        # Modbus TCP 标准端口

# 设置日志
# 创建主日志记录器
logging.basicConfig(
    format="%(asctime)s [%(levelname)s] %(message)s",
    level=logging.DEBUG  # 调整日志级别为 DEBUG 以查看所有通信细节
)

# 启用 pymodbus 的通信日志
logging.getLogger("pymodbus").setLevel(logging.DEBUG)
logging.getLogger("pymodbus.server").setLevel(logging.DEBUG)
logging.getLogger("pymodbus.protocol").setLevel(logging.DEBUG)
logging.getLogger("pymodbus.transaction").setLevel(logging.DEBUG)

# 创建数据存储区

# 生成从 0x0000 开始递增 1 的列表，长度为 100
initial_values = [i for i in range(0x0000, 0x0000 + 1000)]

store = ModbusSlaveContext(
    co=ModbusSequentialDataBlock(1, [True, True, False, False]*25),  # 线圈（Coils）
    di=ModbusSequentialDataBlock(1, [True, True, True, False]*25),  # 离散输入（Discrete Inputs）
    hr=ModbusSequentialDataBlock(1, range(100)),  # 保持寄存器（Holding Registers）
    ir=ModbusSequentialDataBlock(1, range(200,300))   # 输入寄存器（Input Registers）
)

# 创建从站上下文
context = ModbusServerContext(slaves=store, single=True)

# 设备标识信息（可选）
identity = ModbusDeviceIdentification()
identity.VendorName = "MyCompany"
identity.ProductCode = "ModbusServer"
identity.VendorUrl = "https://example.com"
identity.ProductName = "Modbus TCP Server"
identity.ModelName = "ModbusTCP v1.0"
identity.MajorMinorRevision = "1.0"

# 启动 Modbus TCP 服务器
async def run_server():
    logging.info(f"Starting Modbus TCP Server on {HOST}:{PORT}...")

    # 打印寄存器初始值
    slave = context[0]
    # 线圈寄存器
    co_values = slave.getValues(1, 0, 100)
    logging.info(f"Initial values of Coils: {co_values}")
    # 离散输入寄存器
    di_values = slave.getValues(2, 0, 100)
    logging.info(f"Initial values of Discrete Inputs: {di_values}")
    # 保持寄存器
    hr_values = slave.getValues(3, 0, 100)
    logging.info(f"Initial values of Holding Registers: {hr_values}")
    # 输入寄存器
    ir_values = slave.getValues(4, 0, 100)
    logging.info(f"Initial values of Input Registers: {ir_values}")

    await StartAsyncTcpServer(
        context=context,
        identity=identity,
        address=(HOST, PORT)
    )

if __name__ == "__main__":
    try:
        asyncio.run(run_server())
    except KeyboardInterrupt:
        logging.info("Server is shutting down...")
